﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Text;
using System.Threading.Tasks;
#if !DOT_NET
using Windows.Foundation.Metadata;

#else
using StyleMVVM.Data;

#endif

namespace StyleMVVM.DependencyInjection
{
	public sealed class InjectionContext : IInjectionContext
	{
		private Dictionary<string, object> conditions;
		private Dictionary<string, ExportFunction> exportDictionary;
		private Dictionary<string, object> customData;

		public InjectionContext()
		{
		}

		public InjectionContext(IEnumerable<KeyValuePair<string, object>> startingConditions)
		{
			if (startingConditions != null)
			{
				conditions = new Dictionary<string, object>();

				foreach (KeyValuePair<string, object> startingCondition in startingConditions)
				{
					conditions[startingCondition.Key] = startingCondition.Value;
				}
			}
		}

		public Type InjectionType { get; set; }

		public object InjectionTarget { get; set; }

		public object[] InjectionTargetAttributes { get; set; }

		public IDisposalScope DisposalScope { get; set; }

		public IInjectionTargetInfo Target { get; set; }

		public bool IsConditionDefined(string condition)
		{
			if (conditions != null && condition != null && conditions.ContainsKey(condition))
			{
				return true;
			}

			return false;
		}

		public void DefineCondition(string condition)
		{
			if (conditions == null)
			{
				conditions = new Dictionary<string, object>();
			}

			conditions[condition] = true;
		}

		public object GetConditionValue(string condition)
		{
			if (conditions != null && condition != null)
			{
				object returnValue;

				conditions.TryGetValue(condition, out returnValue);

				return returnValue;
			}

			return null;
		}

		public void SetConditionValue(string condition, object newValue)
		{
			if (conditions == null)
			{
				conditions = new Dictionary<string, object>();
			}

			conditions[condition] = newValue;
		}

		[DefaultOverload]
		public void RegisterExport(string exportName, ExportFunction exportFunction)
		{
			if (exportDictionary == null)
			{
				exportDictionary = new Dictionary<string, ExportFunction>();
			}

			exportDictionary[exportName] = exportFunction;
		}

		public void RegisterExport(Type exportType, ExportFunction exportFunction)
		{
			if (exportDictionary == null)
			{
				exportDictionary = new Dictionary<string, ExportFunction>();
			}

			exportDictionary[exportType.FullName] = exportFunction;
		}

		public void RegisterExport(Type exportType, object instance)
		{
			if (exportDictionary == null)
			{
				exportDictionary = new Dictionary<string, ExportFunction>();
			}

			exportDictionary[exportType.FullName] = (x, y, z) => instance;
		}

		public void RegisterExport(string exportName, object instance)
		{
			if (exportDictionary == null)
			{
				exportDictionary = new Dictionary<string, ExportFunction>();
			}

			exportDictionary[exportName] = (x, y, z) => instance;
		}

		[DefaultOverload]
		public object LocateExport(string exportName,
		                           IDependencyInjectionContainer container,
		                           [ReadOnlyArray] object[] constructorParams)
		{
			if (exportDictionary != null)
			{
				ExportFunction exportFunction;

				exportDictionary.TryGetValue(exportName, out exportFunction);

				if (exportFunction != null)
				{
					return exportFunction(container, this, constructorParams);
				}
			}

			return null;
		}

		public object LocateExport(Type exportType,
		                           IDependencyInjectionContainer container,
		                           [ReadOnlyArray] object[] constructorParams)
		{
			if (exportDictionary != null)
			{
				ExportFunction exportFunction;

				exportDictionary.TryGetValue(exportType.FullName, out exportFunction);

				if (exportFunction != null)
				{
					return exportFunction(container, this, constructorParams);
				}
			}

			return null;
		}

		public object GetCustomData(string customDataName)
		{
			object returnValue = null;

			if (customData != null)
			{
				customData.TryGetValue(customDataName, out returnValue);
			}

			return returnValue;
		}

		public void SetCustomData(string customDataName, object newData)
		{
			if (customData == null)
			{
				customData = new Dictionary<string, object>();
			}

			customData[customDataName] = newData;
		}
	}
}